package adventure.room;

import adventure.misc.Currency;
import adventure.misc.CurrencyImp;
import adventure.placeable.Fightable;
import adventure.placeable.Item;
import adventure.placeable.ItemImp;
import adventure.placeable.Mobile;
import adventure.placeable.MobileEdit;
import adventure.placeable.MobileImp;
import adventure.placeable.trigger.Trigger;
import adventure.placeable.trigger.TriggerImp;
import colour.ColourUtil;
import java.util.ArrayList;
import player.Player;
import player.PlayerImp;

/**
 *
 * @author Michael Hanns
 *
 */
public class RoomImp implements Room, RoomEdit, Cloneable {

    private int x;
    private int y;
    private int z;
    private String roomTitle;
    private String roomDescription;
    private int spawnLevel;
    private boolean lowLight;
    private String closed;
    private String locked;
    private String blocked;
    private Currency currencyType;
    private int currencyAmount;
    private ArrayList<Item> items;
    private ArrayList<Mobile> mobiles;
    private ArrayList<Trigger> triggers;
    private ArrayList<Player> players;
    // Counters for repop
    private int repopTickCount;
    private int ticksPassed;
    // Backups for repop.
    private String roomTitle2;
    private String roomDescription2;
    private String closed2;
    private String locked2;
    private String blocked2;
    private int currencyAmount2;
    private ArrayList<Item> items2;
    private ArrayList<Mobile> mobiles2;
    private ArrayList<Trigger> triggers2;

    public RoomImp() {
        this.x = 0;
        this.y = 0;
        this.z = 0;
        this.items = new ArrayList<Item>();
        this.mobiles = new ArrayList<Mobile>();
        this.triggers = new ArrayList<Trigger>();
        this.players = new ArrayList<Player>();
        this.currencyType = new CurrencyImp();
        this.roomTitle = "";
        this.roomDescription = "";
        this.spawnLevel = 0;
        this.lowLight = false;
        this.closed = "";
        this.locked = "";
        this.blocked = "";
        this.currencyAmount = 0;
        this.repopTickCount = 0;
        this.ticksPassed = 0;
    }

    public RoomImp(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.items = new ArrayList<Item>();
        this.mobiles = new ArrayList<Mobile>();
        this.triggers = new ArrayList<Trigger>();
        this.players = new ArrayList<Player>();
        this.currencyType = new CurrencyImp();
        this.roomTitle = "";
        this.roomDescription = "";
        this.spawnLevel = 0;
        this.lowLight = false;
        this.closed = "";
        this.locked = "";
        this.blocked = "";
        this.currencyAmount = 0;
        this.repopTickCount = 0;
        this.ticksPassed = 0;
    }

    // Setters
    @Override
    public void setXYZ(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public void captureInitialState() {
        roomTitle2 = new String(roomTitle);
        roomDescription2 = new String(roomDescription);
        closed2 = new String(closed);
        locked2 = new String(locked);
        blocked2 = new String(blocked);
        currencyAmount2 = currencyAmount;

        items2 = new ArrayList<Item>();
        mobiles2 = new ArrayList<Mobile>();
        triggers2 = new ArrayList<Trigger>();

        for (int c = 0; c < items.size(); c++) {
            items2.add(items.get(c).cloneThis());
        }

        for (int c = 0; c < mobiles.size(); c++) {
            mobiles2.add(mobiles.get(c).cloneThis());
        }

        for (int c = 0; c < triggers.size(); c++) {
            triggers2.add(triggers.get(c).cloneThis());
        }
    }

    @Override
    public void setCurrencyType(Currency type) {
    }

    @Override
    public void setTitle(String title) {
        roomTitle = title;
    }

    @Override
    public void setDescription(String desc) {
        roomDescription = desc;
    }

    @Override
    public void setSpawnLevel(int level) {
        spawnLevel = level;
    }

    @Override
    public void setRepopTickCount(int count) {
        repopTickCount = count;
    }

    @Override
    public void setLowLight(boolean flag) {
        lowLight = flag;
    }

    @Override
    public void setClosed(String doors) {
        closed = doors.toUpperCase();
    }

    @Override
    public void setLocked(String doors) {
        locked = doors.toUpperCase();
    }

    @Override
    public void setBlocked(String doors) {
        blocked = doors.toUpperCase();
    }

    @Override
    public void setCurrencyContents(int value) {
        currencyAmount = value;
    }

    @Override
    public void addItem(Item i) {
        items.add(i);
    }

    @Override
    public void addMobile(Mobile m) {
        ((MobileEdit) m).setX(x);
        ((MobileEdit) m).setY(y);
        ((MobileEdit) m).setZ(z);
        mobiles.add(m);
    }

    @Override
    public void addTrigger(Trigger t) {
        triggers.add(t);
    }

    @Override
    public void removeItem(Item i) {
        items.remove(i);
    }

    @Override
    public void removeItem(int id) {
        boolean found = false;
        for (int c = 0; c > items.size() && !found; c++) {
            if (items.get(c).getID() == id) {
                items.remove(c);
                found = true;
            }
        }
    }

    @Override
    public void removeItemAtIndex(int index) {
        items.remove(index);
    }

    @Override
    public void removeMobile(Mobile m) {
        mobiles.remove(m);
    }

    @Override
    public void removeMobile(int id) {
        boolean found = false;
        for (int c = 0; c > mobiles.size() && !found; c++) {
            if (mobiles.get(c).getID() == id) {
                mobiles.remove(c);
                found = true;
            }
        }
    }

    @Override
    public void removeMobileAtIndex(int index) {
        mobiles.remove(index);
    }

    @Override
    public void removeTrigger(Trigger t) {
        triggers.remove(t);
    }

    @Override
    public void removeTrigger(int id) {
        boolean found = false;
        for (int c = 0; c > triggers.size() && !found; c++) {
            if (triggers.get(c).getID() == id) {
                triggers.remove(c);
                found = true;
            }
        }
    }

    @Override
    public void removeTriggerAtIndex(int index) {
        triggers.remove(index);
    }

    // Getters
    @Override
    public int x() {
        return x;
    }

    @Override
    public int y() {
        return y;
    }

    @Override
    public int z() {
        return z;
    }

    @Override
    public boolean repops() {
        if (repopTickCount > 0) {
            return true;
        }
        return false;
    }

    @Override
    public int getTicksUntilRepop() {
        return repopTickCount;
    }

    @Override
    public boolean tickPassed() {
        ticksPassed++;
        if (ticksPassed >= repopTickCount) {
            ticksPassed = 0;
            repopRoomState();
            return true;
        }
        return false;
    }

    private void repopRoomState() {
        roomTitle = roomTitle2;
        roomDescription = roomDescription2;
        closed = closed2;
        locked = locked2;
        blocked = blocked2;
        currencyAmount = currencyAmount2;
        items = new ArrayList<Item>();
        mobiles = new ArrayList<Mobile>();
        triggers = new ArrayList<Trigger>();

        for (int c = 0; c < items2.size(); c++) {
            items.add(items2.get(c).cloneThis());
        }

        for (int c = 0; c < mobiles2.size(); c++) {
            mobiles.add(mobiles2.get(c).cloneThis());
        }

        for (int c = 0; c < triggers2.size(); c++) {
            triggers.add(triggers2.get(c).cloneThis());
        }
    }

    @Override
    public String getTitle() {
        if (lightPresent()) {
            return roomTitle;
        } else {
            return "Darkness...";
        }
    }

    @Override
    public String getDescription() {
        if (lightPresent()) {
            return roomDescription;
        } else {
            return "You are unable to distinguish your surroundings in the darkness.";
        }
    }

    @Override
    public String getLitTitle() {
        return roomTitle;
    }

    @Override
    public String getLitDescription() {
        return roomDescription;
    }

    @Override
    public String getClosed() {
        return closed;
    }

    @Override
    public String getLocked() {
        return locked;
    }

    @Override
    public String getBlocked() {
        return blocked;
    }

    @Override
    public int getSpawnLevel() {
        return spawnLevel;
    }

    @Override
    public boolean isLowLight() {
        return lowLight;
    }

    @Override
    public String getYouSee(int playerID) {
        String youSee = ColourUtil.colourise("You see:\n", ColourUtil.green);

        boolean lightPresent = lightPresent();

        ArrayList<String> visiblePlaceables = new ArrayList<String>();
        for (int c = 0; c < items.size(); c++) {
            if (items.get(c).isVisible()) {
                if (lightPresent) {
                    visiblePlaceables.add(ColourUtil.colourise(items.get(c).getName(), ColourUtil.item));
                } else {
                    visiblePlaceables.add(ColourUtil.colourise("something", ColourUtil.defaultColour));
                }
            }
        }
        for (int c = 0; c < triggers.size(); c++) {
            if (triggers.get(c).isVisible()) {
                if (lightPresent) {
                    visiblePlaceables.add(ColourUtil.colourise(triggers.get(c).getName(), ColourUtil.trigger));
                } else {
                    visiblePlaceables.add(ColourUtil.colourise("something", ColourUtil.defaultColour));
                }
            }
        }
        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).isVisible()) {
                if (lightPresent) {
                    visiblePlaceables.add(ColourUtil.colourise(mobiles.get(c).getName(), ColourUtil.mobile));
                } else {
                    visiblePlaceables.add(ColourUtil.colourise("someone", ColourUtil.defaultColour));
                }
            }
        }
        for (int c = 0; c < players.size(); c++) {
            if (players.get(c).getID() != playerID) {
                if (lightPresent) {
                    visiblePlaceables.add(ColourUtil.colourise(players.get(c).getName(), ColourUtil.player));
                } else {
                    visiblePlaceables.add(ColourUtil.colourise("someone", ColourUtil.defaultColour));
                }
            }
        }


        if (currencyAmount > 0 || visiblePlaceables.size() > 0) {
            if (visiblePlaceables.size() > 0) {
                youSee = youSee.concat(visiblePlaceables.get(0));
                for (int c = 1; c < visiblePlaceables.size(); c++) {
                    youSee = youSee.concat(ColourUtil.colourise(", ", ColourUtil.defaultColour).concat(
                            visiblePlaceables.get(c)));
                }

                if (currencyAmount > 0) {
                    if (lightPresent) {
                        String currencyName;
                        if (currencyAmount > 1) {
                            currencyName = currencyAmount + " " + currencyType.getPlural();
                        } else {
                            currencyName = "a " + currencyType.getSingular();
                        }

                        youSee = youSee.concat(ColourUtil.colourise(", ", ColourUtil.defaultColour)
                                + ColourUtil.colourise(currencyName + "\n",
                                ColourUtil.currency));
                    } else {
                        String currencyName;
                        if (currencyAmount > 1) {
                            currencyName = currencyType.getPluralInDark();
                        } else {
                            currencyName = currencyType.getSingularInDark();
                        }

                        youSee = youSee.concat(ColourUtil.colourise(", ", ColourUtil.defaultColour) + currencyName + "\n");
                    }
                } else {
                    youSee = youSee.concat("\n");
                }
            } else {
                if (lightPresent) {
                    String currencyName;
                    if (currencyAmount > 1) {
                        currencyName = currencyAmount + " " + currencyType.getPlural();
                    } else {
                        currencyName = "a " + currencyType.getSingular();
                    }

                    youSee = youSee + ColourUtil.colourise(currencyName + "\n",
                            ColourUtil.currency);
                } else {
                    String currencyName;
                    if (currencyAmount > 1) {
                        currencyName = currencyType.getPluralInDark();
                    } else {
                        currencyName = currencyType.getSingularInDark();
                    }

                    youSee = youSee.concat(currencyName + "\n");
                }
            }
        } else {
            youSee = youSee.concat(ColourUtil.colourise("nothing of interest\n", ColourUtil.defaultColour));
        }

        return youSee;
    }

    @Override
    public boolean isBlocked(char dir) {
        for (int c = 0; c < blocked.length(); c++) {
            if (blocked.charAt(c) == dir) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isClosed(char dir) {
        for (int c = 0; c < closed.length(); c++) {
            if (closed.charAt(c) == dir) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isLocked(char dir) {
        for (int c = 0; c < locked.length(); c++) {
            if (locked.charAt(c) == dir) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int getCurrencyContents() {
        return currencyAmount;
    }

    @Override
    public Item getItem(String item) {
        for (int c = 0; c < items.size(); c++) {
            if (items.get(c).getName().equalsIgnoreCase(item)) {
                return items.get(c);
            }
        }
        Item noShow = new ItemImp();
        return noShow;
    }

    @Override
    public int getItemIDAtPosition(int pos) {
        if (pos < items.size()) {
            return items.get(pos).getID();
        }
        return 0;
    }

    @Override
    public Item takeItem(String item) {
        Item i = getItem(item);
        if (i.getID() > 0) {
            items.remove(i);
        }

        return i;
    }

    @Override
    public boolean hasContent() {
        if (currencyAmount > 0 || items.size() > 0 || mobiles.size() > 0 || triggers.size() > 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean hasItem(int id, int quant) {
        int total = 0;
        for (int c = 0; c < items.size(); c++) {
            if (items.get(c).getID() == id) {
                total++;
                if (total == quant) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean hasMobile(int id, int quant) {
        int total = 0;
        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).getID() == id) {
                total++;
                if (total == quant) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Mobile getMobile(String mob) {
        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).getName().equalsIgnoreCase(mob)) {
                return mobiles.get(c);
            }
        }
        Mobile noShow = new MobileImp();
        return noShow;
    }

    @Override
    public Mobile getMobileAtPosition(int pos) {
        if (pos < mobiles.size()) {
            return mobiles.get(pos);
        }
        return new MobileImp();
    }

    @Override
    public int getMobileIDAtPosition(int pos) {
        if (pos < mobiles.size()) {
            return mobiles.get(pos).getID();
        }
        return 0;
    }

    @Override
    public boolean hasTrigger(int id, int quant) {
        int total = 0;
        for (int c = 0; c < triggers.size(); c++) {
            if (triggers.get(c).getID() == id) {
                total++;
                if (total == quant) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Trigger getTrigger(String trigger) {
        for (int c = 0; c < triggers.size(); c++) {
            if (triggers.get(c).getName().equalsIgnoreCase(trigger)) {
                return triggers.get(c);
            }
        }
        Trigger noShow = new TriggerImp();
        return noShow;
    }

    @Override
    public int getTriggerIDAtPosition(int pos) {
        if (pos < triggers.size()) {
            return triggers.get(pos).getID();
        }
        return 0;
    }

    @Override
    public Player getPlayer(String player) {
        for (int c = 0; c < players.size(); c++) {
            if (players.get(c).getName().equalsIgnoreCase(player)) {
                return players.get(c);
            }
        }
        Player noShow = new PlayerImp();
        return noShow;
    }

    @Override
    public ArrayList<Mobile> getAggroMobs(int p) {
        ArrayList<Mobile> aggroMobs = new ArrayList<Mobile>();
        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).isAggro(p)) {
                aggroMobs.add(mobiles.get(c));
            }
        }
        return aggroMobs;
    }

    @Override
    public void addCurrencyAmount(int amount) {
        currencyAmount += amount;
    }

    @Override
    public int takeCurrencyAmount(int amount) {
        if (amount > currencyAmount) {

            int amountTaken = currencyAmount;
            currencyAmount = 0;

            for (int c = 0; c < mobiles.size() && amountTaken < amount; c++) {
                amountTaken += mobiles.get(c).takeCurrencyAmount(amount - amountTaken);
            }

            return amountTaken;
        } else {
            currencyAmount = currencyAmount - amount;

            return amount;
        }

    }

    @Override
    public int takeAllCurrency() {
        int amount = currencyAmount;
        currencyAmount = 0;

        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).isDead() && mobiles.get(c).getCurrencyContents() > 0) {
                amount += mobiles.get(c).getCurrencyContents();
                mobiles.get(c).takeCurrencyAmount(mobiles.get(c).getCurrencyContents());
            }
        }

        return amount;
    }

    @Override
    public void open(char dir) {
        String tempClosed = "";
        for (int c = 0; c < closed.length(); c++) {
            if (closed.charAt(c) != dir) {
                tempClosed = tempClosed.concat(String.valueOf(closed.charAt(c)));
            }
        }
        closed = tempClosed;
    }

    @Override
    public void close(char dir) {
        closed += dir;
    }

    // Returns true if exit is closeable
    @Override
    public boolean closeableExit(char dir) {
        if (closed2.toUpperCase().contains(dir + "")) {
            return true;
        }
        return false;
    }

    @Override
    public void unlock(char dir) {
        String tempLocked = "";
        for (int c = 0; c < locked.length(); c++) {
            if (locked.charAt(c) != dir) {
                tempLocked = tempLocked.concat(String.valueOf(locked.charAt(c)));
            }
        }
        locked = tempLocked;
    }

    @Override
    public void aggroAllMobs() {
        for (int c = 0; c < mobiles.size(); c++) {
            ((MobileEdit) mobiles.get(c)).setAggro(true);
        }
    }

    @Override
    public String aggroMobsAttack(int p) {
        String output = "";
        for (int c = 0; c < mobiles.size(); c++) {
            if (!mobiles.get(c).isDead() && mobiles.get(c).isAggro(p)) {
                // The 'spark' should be top of the mobiles hit list.
                boolean found = false;
                for (int d = 0; d < players.size() && !found; d++) {
                    if (players.get(d).getID() == p) {
                        if (!players.get(d).isDead() && !mobiles.get(c).isFighting(p)) {
                            if (output.length() == 0) {
                                output = "You have been attacked by "
                                        + ColourUtil.colourise(
                                        mobiles.get(c).getAliveName(), ColourUtil.mobile)
                                        + "!";
                            } else {
                                output += "\nYou have been attacked by "
                                        + ColourUtil.colourise(
                                        mobiles.get(c).getAliveName(), ColourUtil.mobile)
                                        + "!";
                            }
                            ((Fightable) mobiles.get(c)).attack((Fightable) players.get(d));
                        }
                        found = true;
                    }
                }
            }
        }
        return output;
    }

    @Override
    public String[][] aggroGroupsAttack(int p) {
        String[][] output;
        Player player;
        Player[] group;
        for (int c = 0; c < players.size(); c++) {
            if (players.get(c).getID() == p) {
                player = players.get(c);
                group = player.getLocalGroup();
                output = new String[group.length + 2][2];

                for (int d = 0; d < group.length; d++) {
                    if (group[d].inCombat() && !players.get(c).inCombat()) {
                        Fightable[] targets = group[d].getLocalTargets();


                        if (targets.length > 0 && !targets[0].isPlayer()) {
                            player.attack((Fightable) targets[0]);

                            // Set player attacker output
                            output[0][0] = "" + player.getID();
                            output[0][1] = "\nYou attack "
                                    + ColourUtil.colourise(group[d].getAliveName(), ColourUtil.player)
                                    + "'s target "
                                    + ColourUtil.colourise(targets[0].getAliveName(), ColourUtil.mobile)
                                    + "!";

                            // Set group output
                            for (int e = 1; e <= group.length; e++) {
                                output[e][0] = "" + group[e].getID();

                                // If group member who's target is getting hit
                                if (e == d) {
                                    output[e][1] = "\n"
                                            + ColourUtil.colourise(player.getAliveName(), ColourUtil.player)
                                            + " attacks your target "
                                            + ColourUtil.colourise(targets[0].getAliveName(), ColourUtil.mobile)
                                            + "!";
                                } else {
                                    output[e][1] = "\n"
                                            + ColourUtil.colourise(player.getAliveName(), ColourUtil.player)
                                            + " attacks "
                                            + ColourUtil.colourise(group[e].getAliveName(), ColourUtil.player)
                                            + "'s target "
                                            + ColourUtil.colourise(targets[0].getAliveName(), ColourUtil.mobile)
                                            + "!";
                                }
                            }

                            return output;
                        } else if (targets.length > 0) {
                            player.attack((Fightable) targets[0]);

                            // Set player attacker output
                            output[0][0] = "" + player.getID();
                            output[0][1] = "\nYou attack "
                                    + ColourUtil.colourise(group[d].getAliveName(), ColourUtil.player)
                                    + "'s target "
                                    + ColourUtil.colourise(targets[0].getAliveName(), ColourUtil.player)
                                    + "!";

                            // Set player target output
                            output[1][0] = "" + ((Player) targets[0]).getID();
                            output[1][1] = ColourUtil.colourise(player.getAliveName(), ColourUtil.player)
                                    + " attacks "
                                    + ColourUtil.colourise(group[d].getAliveName(), ColourUtil.player)
                                    + "'s target - YOU!";

                            // Set group output
                            for (int e = 2; e <= group.length - 2; e++) {
                                output[e][0] = "" + group[e].getID();

                                // If group member who's target is getting hit
                                if (e == d) {
                                    output[e][1] = "\n"
                                            + ColourUtil.colourise(player.getAliveName(), ColourUtil.player)
                                            + " attacks your target "
                                            + ColourUtil.colourise(targets[0].getAliveName(),
                                            ColourUtil.player) + "!";
                                } else {
                                    output[e][1] = "\n"
                                            + ColourUtil.colourise(player.getAliveName(), ColourUtil.player)
                                            + " attacks "
                                            + ColourUtil.colourise(group[e].getAliveName(), ColourUtil.player)
                                            + "'s target "
                                            + ColourUtil.colourise(targets[0].getAliveName(), ColourUtil.player)
                                            + "!";
                                }
                            }
                        }
                        return output;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void stopFighting(Player p) {
        for (int c = 0; c < mobiles.size(); c++) {
            mobiles.get(c).stopFighting(p);
        }

        for (int c = 0; c < players.size(); c++) {
            players.get(c).stopFighting((Fightable) p);
        }
    }

    @Override
    public String returnTriggerOutput(RoomManager r, Player triggerP, String input) {
        String result = "";
        for (int c = 0; c < triggers.size(); c++) {
            result = result + triggers.get(c).tripTriggers(r, triggerP, input);
            if (result.equals("\n")) {
                result = "";
            }
        }
        return result;
    }

    @Override
    public String decayEmptyCorpses() {
        String returnText = "";
        for (int n = 0; n < mobiles.size(); n++) {
            if (mobiles.get(n).isDead() && mobiles.get(n).getInventoryItem(0).getID() == 0
                    && mobiles.get(n).getCurrencyContents() == 0) {
                returnText = returnText.concat("The ".concat(
                        ColourUtil.colourise(mobiles.get(n).getName(), ColourUtil.mobile).concat(" crumbles into dust.\n")));
                mobiles.remove(n);
            }
        }
        return returnText;
    }

    @Override
    public String decayTempItems() {
        String returnText = "";
        String decayText;
        // Decay items on floor
        for (int n = 0; n < items.size(); n++) {
            System.out.println(items.get(n).getName() + ":" + items.get(n).isTemporary() + "/"
                    + items.get(n).getTicksRemaining());
            decayText = items.get(n).decay();

            if (decayText.length() > 0) {
                returnText += decayText + "\n";
                items.remove(n);
                n = 0;
            }
        }

        for (int n = 0; n < players.size(); n++) {
            decayText = players.get(n).decayTempItems();

            if (decayText.length() > 0) {
                returnText += decayText + "\n";
                items.remove(n);
                n = 0;
            }
        }

        if (returnText.length() > 0) {
            System.out.println(returnText.substring(0, returnText.length() - 1));
            return returnText.substring(0, returnText.length() - 1);
        }

        return "";
    }

    @Override
    public void playerEnters(Player p) {
        players.add(p);
    }

    @Override
    public void playerLeaves(Player p) {
        players.remove(p);
    }

    // Helper methods
    @Override
    public boolean lightPresent() {
        System.out.println("Into lightpresent()");
        if (!lowLight) {
            return true;
        }

        for (int c = 0; c < items.size(); c++) {
            if (items.get(c).isLightSource()) {
                return true;
            }
        }

        for (int c = 0; c < mobiles.size(); c++) {
            if (mobiles.get(c).isLightSource()) {
                return true;
            }
        }

        for (int c = 0; c < triggers.size(); c++) {
            if (triggers.get(c).isLightSource()) {
                return true;
            }
        }

        for (int c = 0; c < players.size(); c++) {
            if (players.get(c).lightSourceEquipped()) {
                return true;
            }
        }

        return false;
    }

    @Override
    public Room cloneThis() {
        Room newClone = new RoomImp();
        try {
            newClone = (RoomImp) this.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newClone;
    }

    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            ((RoomImp) clone).roomTitle = new String(this.roomTitle);
            ((RoomImp) clone).roomDescription = new String(this.roomDescription);
            ((RoomImp) clone).closed = new String(this.closed);
            ((RoomImp) clone).locked = new String(this.locked);
            ((RoomImp) clone).blocked = new String(this.blocked);
            ((RoomImp) clone).items = new ArrayList<Item>();
            ((RoomImp) clone).mobiles = new ArrayList<Mobile>();
            ((RoomImp) clone).triggers = new ArrayList<Trigger>();
            ((RoomImp) clone).players = new ArrayList<Player>();
            for (int c = 0; c < items.size(); c++) {
                ((RoomImp) clone).items.add(items.get(c).cloneThis());
            }

            for (int c = 0; c < mobiles.size(); c++) {
                ((RoomImp) clone).mobiles.add(mobiles.get(c).cloneThis());
            }

            for (int c = 0; c < triggers.size(); c++) {
                ((RoomImp) clone).triggers.add(triggers.get(c).cloneThis());
            }
            ((RoomImp) clone).captureInitialState();
            return clone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
